#include <iostream>
#include <math.h>
#include <cstdlib>
#include <time.h>

/*  linear_regression.cpp
*   This program is part of the °Simple-Benchs° Benchmark
*   The complexity of this program is O(n) where n is the number of pairs.
*
*   
*   To run the program: ./program Number_of_points Max_element
*/

/* Program standart output. Display the pairs.  Complexity O(n) where n is the number of pairs */
void displayAxis(float *Xaxis, float *Yaxis, int size){
  int count;
  std::cout<<"\n\tSimple Linear Regression\n================= Axis =================\n";
  std::cout<<"    X axis\t\tY axis\n\n";
  for (count=0; count<size;count++){
    std::cout<<"\t"<<Xaxis[count]<<"\t\t"<<Yaxis[count]<<"\n";
  }
  std::cout<<"\n";
  std::cout<<"    X axis\t\tY axis\n\n========================================\n\n";
}

/* Perform the computation of the linear regression and the correlation coeficient as well. Complecity O(n), where n is the
amount of pairs generated */
void Calc(float *Xaxis, float *Yaxis, int size){
  double SumX = 0;
  double SumXX = 0;
  double SumY = 0;
  double SumYY = 0;
  double SumXY = 0;
  float B, A, correl;
  int count;
  for (count = 0; count< size; count++){
    SumX += Xaxis[count];
    SumY += Yaxis[count];
    SumXY += Xaxis[count]*Yaxis[count];
    SumXX += Xaxis[count]*Xaxis[count];
    SumYY += Yaxis[count]*Yaxis[count];
  }
  B = ((size*SumXY - SumX*SumY)/(size*SumXX - SumX*SumX));
  A = (SumY/size) - ((B*SumX)/size);
  correl = (size*SumXY - SumX*SumY)/sqrt((size*SumXX - SumX*SumX)*(size*SumYY - SumY*SumY));
  std::cout<<"Sum Xaxis = "<<SumX<<"\nSum Xaxis*Xaxis = " <<SumXX<<"\nSum Yaxis = "<<SumY<<"\nSum Yaxis*Yaxis = "<<SumYY<<"\
    \nSum Xaxis*Yaxis = "<<SumXY<<"\n\
    \nEquation of the straight line:\n(y = "<<B<<"*x + "<<A<<")\n\nCorrelation Coeficient = "<<correl<<"\n\n";
}


/* Initialization of the axis. Complexity O(n) where n is the number of pairs*/
void GenAxis(float *Xaxis, float *Yaxis, int size, int max) {
  int count;
  for (count = 0; count < size; count++){
    Xaxis[count] = (float)(rand() % max);
    Yaxis[count] = Xaxis[count] + ((float)(rand() % max));  
  }
}

/*  Initial check to verify whether the amount of arguments is correct or not.  Complexity O(1) */
short Initial_check(int inputs){
  if (inputs != 3) {
    std::cerr<<"Wrong number of argments. Syntax: ./program Number_of_points Max_element\n";
    return 1;
  }
  return 0;
}


int main(int argc, char **argv){

  /* Checking arguments */
  if (Initial_check(argc)) return 1;

  /* Retrieve problem size. */
  int size = atoi(argv[1]);
  int max_gen = atoi(argv[2]);

  /* Seed initialization. */
  srand((unsigned)time(NULL));

  /* Variable declaration/allocation/initialization. */
  float *Xaxis;
  float *Yaxis;  
  Xaxis = new float[size];
  Yaxis = new float[size];
  GenAxis(Xaxis,Yaxis,size,max_gen);

  /* Display the generated axis*/   
  displayAxis(Xaxis, Yaxis, size);

  /*  Computing the Linear Regression */
  Calc(Xaxis,Yaxis,size);
  
  /* Be clean. */
  delete [] Xaxis;
  delete [] Yaxis;
  
  return 0;
}